package com.bsg.upm.service;

import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bsg.upm.check.CheckResult;
import com.bsg.upm.check.DatabaseCheck;
import com.bsg.upm.constant.DictConstants;
import com.bsg.upm.constant.DictTypeConstants;
import com.bsg.upm.constant.OperateDictConstants;
import com.bsg.upm.constant.OperateDictTypeConstants;
import com.bsg.upm.dto.DatabaseDto;
import com.bsg.upm.entity.ServEntity;
import com.bsg.upm.entity.SubServEntity;
import com.bsg.upm.exception.APIException;
import com.bsg.upm.http.RespJson;
import com.bsg.upm.http.RespJsonFactory;

/**
 * 数据库管理业务处理类
 * 
 * @author HCK
 *
 */
@Service
public class DatabaseService extends BaseService {

	@Resource
	private DatabaseCheck databaseCheck;

	/**
	 * 获取数据库列表
	 * 
	 * @param servId
	 *            服务编码
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	public RespJson list(String servId) throws APIException {
		try {
			JSONArray results = new JSONArray();

			// 获取指定的服务
			ServEntity serv = servDao.getBase(servId);
			if (serv == null) {
				return RespJsonFactory.build(HttpStatus.SC_GONE, "该服务不存在");
			}

			List<SubServEntity> subServs = serv.getSubServs();
			boolean canSave = false;
			for (SubServEntity subServ : subServs) {
				if (DictConstants.DATABASE_TYPE_RDS.equals(subServ.getSubOrder().getDefinitionSubServ().getType())) {
					canSave = true;
					break;
				}
			}
			if (!canSave) {
				return RespJsonFactory.build(HttpStatus.SC_BAD_REQUEST, "该类型服务无数据库");
			}

			// 获取主单元关联名称
			Map<String, String> masterMap = getMasterUnitRelateName(serv);

			// 判断是否存在主单元
			boolean existMasterUnit = existMaster(masterMap);
			if (!existMasterUnit) {
				throw new APIException("获取不到主单元");
			}

			// 站点
			String siteId = serv.getOrder().getArea().getSite().getId();
			for (SubServEntity subServ : subServs) {
				if (DictConstants.DATABASE_TYPE_RDS.equals(subServ.getSubOrder().getDefinitionSubServ().getType())) {
					// 单元关联名称
					String unitRelateName = masterMap.get(subServ.getRelateId());
					if (StringUtils.isNotBlank(unitRelateName)) {
						// 构建执行查询数据库接口参数
						String param = buildParamForExec("list", unitRelateName);

						// 从MGM获取数据库信息
						String databaseInfo = executeMgmExec(siteId, subServ.getRelateId(), param);
						if (StringUtils.isNotBlank(databaseInfo)) {
							String[] databaseArr = databaseInfo.split("\\n");
							for (int i = 0; i < databaseArr.length; i++) {
								if (StringUtils.isNotBlank(databaseArr[i])) {
									String[] arr = databaseArr[i].split(",");
									DatabaseDto databaseDto = new DatabaseDto();
									databaseDto.setName(arr[0]);
									databaseDto.setCharacterSet(arr[1]);
									databaseDto.setCharacterSetText(
											dictTypeCache.getTextFromCache(DictTypeConstants.CHARACTER_SET, arr[1]));
									results.add(databaseDto);
								}
							}
						}
						break;
					}
				}
			}
			return RespJsonFactory.buildOK(results);
		} catch (Exception e) {
			logger.error("数据库查询异常", e);
			throw new APIException("数据库查询异常:" + e.getMessage());
		}
	}

	/**
	 * 数据库新增
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	@Transactional(rollbackFor = APIException.class)
	public RespJson save(Map<String, Object> paramMap) throws APIException {
		// 操作动作
		String operateAcion = OperateDictConstants.ACTION_ADD;
		String operateAcionText = dictTypeCache.getTextFromCache(OperateDictTypeConstants.OPERATE_ACTION, operateAcion);
		try {
			// 新增检查
			CheckResult chkRS = databaseCheck.checkSave(paramMap);
			if (chkRS.isError()) {
				return RespJsonFactory.build(chkRS.getStatus(), chkRS.getErrorMsg());
			}

			String servId = (String) paramMap.get("servId");

			// 获取指定的服务
			ServEntity serv = servDao.getBase(servId);

			// 获取主单元关联名称
			Map<String, String> masterMap = getMasterUnitRelateName(serv);
			for (Map.Entry<String, String> entry : masterMap.entrySet()) {
				if (StringUtils.isBlank(entry.getValue())) {
					throw new APIException("存在分片没有主单元");
				}
			}

			// 站点
			String siteId = serv.getOrder().getArea().getSite().getId();
			List<SubServEntity> subServs = serv.getSubServs();
			for (SubServEntity subServ : subServs) {
				if (DictConstants.DATABASE_TYPE_RDS.equals(subServ.getSubOrder().getDefinitionSubServ().getType())) {
					// 构建执行新增数据库接口参数
					String param = buildParamForExec("add", masterMap.get(subServ.getRelateId()),
							(String) paramMap.get("name"), (String) paramMap.get("characterSet"));

					// 向MGM新增数据库信息
					executeMgmExec(siteId, subServ.getRelateId(), param);
				}
			}

			// 保存操作日志
			saveOperateLog(OperateDictConstants.MODEL_DATABASE, operateAcion, (String) paramMap.get("name"),
					(String) paramMap.get("name"));

			return RespJsonFactory.buildCreated();
		} catch (Exception e) {
			logger.error("数据库" + operateAcionText + "异常", e);
			throw new APIException("数据库" + operateAcionText + "异常" + e.getMessage());
		}
	}

	/**
	 * 数据库编辑
	 * 
	 * @param paramMap
	 *            请求参数
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	@Transactional(rollbackFor = APIException.class)
	public RespJson update(Map<String, Object> paramMap) throws APIException {
		// 操作动作
		String operateAcion = OperateDictConstants.ACTION_UPDATE;
		String operateAcionText = dictTypeCache.getTextFromCache(OperateDictTypeConstants.OPERATE_ACTION, operateAcion);
		try {
			// 新增检查
			CheckResult chkRS = databaseCheck.checkUpdate(paramMap);
			if (chkRS.isError()) {
				return RespJsonFactory.build(chkRS.getStatus(), chkRS.getErrorMsg());
			}

			String servId = (String) paramMap.get("servId");

			// 获取指定的服务
			ServEntity serv = servDao.getBase(servId);

			// 获取主单元关联名称
			Map<String, String> masterMap = getMasterUnitRelateName(serv);
			for (Map.Entry<String, String> entry : masterMap.entrySet()) {
				if (StringUtils.isBlank(entry.getValue())) {
					throw new APIException("存在分片没有主单元");
				}
			}

			// 站点
			String siteId = serv.getOrder().getArea().getSite().getId();
			List<SubServEntity> subServs = serv.getSubServs();
			for (SubServEntity subServ : subServs) {
				if (DictConstants.DATABASE_TYPE_RDS.equals(subServ.getSubOrder().getDefinitionSubServ().getType())) {
					// 构建执行新增数据库接口参数
					String param = buildParamForExec("update", masterMap.get(subServ.getRelateId()),
							(String) paramMap.get("name"), (String) paramMap.get("characterSet"));

					// 向MGM编辑数据库信息
					executeMgmExec(siteId, subServ.getRelateId(), param);
				}
			}

			// 保存操作日志
			saveOperateLog(OperateDictConstants.MODEL_DATABASE, operateAcion, (String) paramMap.get("name"),
					(String) paramMap.get("name"));

			return RespJsonFactory.buildOK();
		} catch (Exception e) {
			logger.error("数据库" + operateAcionText + "异常", e);
			throw new APIException("数据库" + operateAcionText + "异常" + e.getMessage());
		}
	}

	/**
	 * 数据库删除
	 * 
	 * @param servId
	 *            服务编码
	 * @param databaseName
	 *            数据库名
	 * @return 操作结果
	 * @throws APIException
	 *             API异常处理类
	 */
	@Transactional(rollbackFor = APIException.class)
	public RespJson remove(String servId, String databaseName) throws APIException {
		// 操作动作
		String operateAcion = OperateDictConstants.ACTION_REMOVE;
		String operateAcionText = dictTypeCache.getTextFromCache(OperateDictTypeConstants.OPERATE_ACTION, operateAcion);
		try {
			// 获取指定服务
			ServEntity serv = servDao.getBase(servId);

			// 删除检查
			CheckResult chkRS = databaseCheck.checkRemove(serv);
			if (chkRS.isError()) {
				return RespJsonFactory.build(chkRS.getStatus(), chkRS.getErrorMsg());
			}

			// 获取主单元关联名称
			Map<String, String> masterMap = getMasterUnitRelateName(serv);
			for (Map.Entry<String, String> entry : masterMap.entrySet()) {
				if (StringUtils.isBlank(entry.getValue())) {
					throw new APIException("存在分片没有主单元");
				}
			}

			String siteId = serv.getOrder().getArea().getSite().getId();
			List<SubServEntity> subServs = serv.getSubServs();
			for (SubServEntity subServ : subServs) {
				if (DictConstants.DATABASE_TYPE_RDS.equals(subServ.getSubOrder().getDefinitionSubServ().getType())) {
					// 构建执行删除数据库接口参数
					String param = buildParamForExec("delete", masterMap.get(subServ.getRelateId()), databaseName);

					// 从MGM删除数据库信息
					executeMgmExec(siteId, subServ.getRelateId(), param);
				}
			}

			// 保存操作日志
			saveOperateLog(OperateDictConstants.MODEL_DATABASE, operateAcion, databaseName, databaseName);

			return RespJsonFactory.buildNoContent();
		} catch (Exception e) {
			logger.error("数据库" + operateAcionText + "异常", e);
			throw new APIException("数据库" + operateAcionText + "异常" + e.getMessage());
		}
	}

	/**
	 * 构建执行exec接口参数
	 * 
	 * @param type
	 *            动作类型
	 * @param masterUnitIdOrName
	 *            单元关联编码/名称
	 * @param databaseName
	 *            数据库名
	 * @return exec接口参数
	 */
	private String buildParamForExec(String type, String masterUnitIdOrName, String databaseName) {
		return buildParamForExec(type, masterUnitIdOrName, databaseName, null);
	}

	/**
	 * 构建执行exec接口参数
	 * 
	 * @param type
	 *            动作类型
	 * @param masterUnitIdOrName
	 *            单元关联编码/名称
	 * @return exec接口参数
	 */
	private String buildParamForExec(String type, String masterUnitIdOrName) {
		return buildParamForExec(type, masterUnitIdOrName, null);
	}

	/**
	 * 构建执行exec接口参数
	 * 
	 * @param type
	 *            动作类型
	 * @param masterUnitIdOrName
	 *            单元关联编码/名称
	 * @param databaseName
	 *            数据库名
	 * @param characterSet
	 *            字符集
	 * @return exec接口参数
	 */
	private String buildParamForExec(String type, String masterUnitIdOrName, String databaseName, String characterSet) {
		JSONObject paramJson = new JSONObject();
		paramJson.put("nameOrID", masterUnitIdOrName);

		JSONArray cmdJsonArr = new JSONArray();
		paramJson.put("cmd", cmdJsonArr);

		cmdJsonArr.add("/root/db_mgm.sh");
		cmdJsonArr.add(type);
		if (StringUtils.isNotBlank(databaseName)) {
			cmdJsonArr.add(databaseName);
		}
		if (StringUtils.isNotBlank(characterSet)) {
			cmdJsonArr.add(characterSet);
		}
		return paramJson.toJSONString();
	}
}
